﻿#include "MapCode.h"
#include "../../Shared/Enums.h"
#include "MonsterObject.h"
#include "../Settings.h"
#include "../Forms/Client.CMain.h"

namespace Client::MirObjects
{

    void CellInfo::AddObject(MapObject *ob)
    {
        if (CellObjects.empty())
        {
            CellObjects = std::vector<MapObject*>();
        }

        CellObjects.Insert(0, ob);
        Sort();
    }

    void CellInfo::RemoveObject(MapObject *ob)
    {
        CellObjects.Remove(ob);

        if (CellObjects.empty())
        {
            CellObjects = std::vector<MapObject*>();
        }
        else
        {
            Sort();
        }
    }

    MapObject *CellInfo::FindObject(unsigned int ObjectID)
    {
        return CellObjects.Find([&] (MapObject *mo)
        {
            return mo->ObjectID == ObjectID;
        });
    }

    void CellInfo::DrawObjects()
    {
        if (CellObjects.empty())
        {
            return;
        }

        for (int i = 0; i < CellObjects.size(); i++)
        {
            if (!CellObjects[i]->Dead)
            {
                CellObjects[i]->Draw();
                continue;
            }

            if (CellObjects[i]->getRace() == ObjectType::Monster)
            {
                switch ((static_cast<MonsterObject*>(CellObjects[i]))->BaseImage)
                {
                    case Monster::PalaceWallLeft:
                    case Monster::PalaceWall1:
                    case Monster::PalaceWall2:
                    case Monster::SSabukWall1:
                    case Monster::SSabukWall2:
                    case Monster::SSabukWall3:
                    case Monster::HellLord:
                        CellObjects[i]->Draw();
                        break;
                    default:
                        continue;
                }
            }
        }
    }

    void CellInfo::DrawDeadObjects()
    {
        if (CellObjects.empty())
        {
            return;
        }
        for (int i = 0; i < CellObjects.size(); i++)
        {
            if (!CellObjects[i]->Dead)
            {
                continue;
            }

            if (CellObjects[i]->getRace() == ObjectType::Monster)
            {
                switch ((static_cast<MonsterObject*>(CellObjects[i]))->BaseImage)
                {
                    case Monster::PalaceWallLeft:
                    case Monster::PalaceWall1:
                    case Monster::PalaceWall2:
                    case Monster::SSabukWall1:
                    case Monster::SSabukWall2:
                    case Monster::SSabukWall3:
                    case Monster::HellLord:
                        continue;
                }
            }

            CellObjects[i]->Draw();
        }
    }

    void CellInfo::Sort()
    {
//C# TO C++ CONVERTER TODO TASK: The 'Compare' parameter of std::sort produces a boolean value, while the .NET Comparison parameter produces a tri-state result:
//ORIGINAL LINE: CellObjects.Sort((MapObject ob1, MapObject ob2) =>
        std::sort(CellObjects.begin(), CellObjects.end(), [&] (MapObject *ob1, MapObject *ob2)
        {
            if (ob1->getRace() == ObjectType::Item && ob2->getRace() != ObjectType::Item)
            {
                return -1;
            }
            if (ob2->getRace() == ObjectType::Item && ob1->getRace() != ObjectType::Item)
            {
                return 1;
            }
            if (ob1->getRace() == ObjectType::Spell && ob2->getRace() != ObjectType::Spell)
            {
                return -1;
            }
            if (ob2->getRace() == ObjectType::Spell && ob1->getRace() != ObjectType::Spell)
            {
                return 1;
            }
    
            int i = ob2->Dead.CompareTo(ob1->Dead);
            return i == 0 ? ob1->ObjectID.CompareTo(ob2->ObjectID) : i;
        });
    }

    MapReader::MapReader(const std::string &FileName)
    {
        this->FileName = FileName;

        initiate();
    }

    void MapReader::initiate()
    {
        if (FileSystem::fileExists(FileName))
        {
            Bytes = File::ReadAllBytes(FileName);
        }
        else
        {
            Width = 1000;
            Height = 1000;
//C# TO C++ CONVERTER NOTE: The following call to the 'RectangularVectors' helper class reproduces the rectangular array initialization that is automatic in C#:
//ORIGINAL LINE: MapCells = new CellInfo[Width, Height];
            MapCells = RectangularVectors::RectangularCellInfoVector(Width, Height);

            for (int x = 0; x < Width; x++)
            {
                for (int y = 0; y < Height; y++)
                {
                    MapCells[x][y] = new CellInfo();
                }
            }
            return;
        }


        //c# custom map format
        if ((Bytes[2] == 0x43) && (Bytes[3] == 0x23))
        {
            LoadMapType100();
            return;
        }

        //wemade mir3 maps have no title they just start with blank bytes
        if (Bytes[0] == 0)
        {
            LoadMapType5();
            return;
        }
        //shanda mir3 maps start with title: (C) SNDA, MIR3.
        if ((Bytes[0] == 0x0F) && (Bytes[5] == 0x53) && (Bytes[14] == 0x33))
        {
            LoadMapType6();
            return;
        }
        //wemades antihack map (laby maps) title start with: Mir2 AntiHack
        if ((Bytes[0] == 0x15) && (Bytes[4] == 0x32) && (Bytes[6] == 0x41) && (Bytes[19] == 0x31))
        {
            LoadMapType4();
            return;
        }
        //wemades 2010 map format i guess title starts with: Map 2010 Ver 1.0
        if ((Bytes[0] == 0x10) && (Bytes[2] == 0x61) && (Bytes[7] == 0x31) && (Bytes[14] == 0x31))
        {
            LoadMapType1();
            return;
        }
        //shanda's 2012 format and one of shandas(wemades) older formats share same header info, only difference is the filesize
        if ((Bytes[4] == 0x0F) || (Bytes[4] == 0x03) && (Bytes[18] == 0x0D) && (Bytes[19] == 0x0A))
        {
            int W = Bytes[0] + (Bytes[1] << 8);
            int H = Bytes[2] + (Bytes[3] << 8);
            if (Bytes.size() > (52 + (W * H * 14)))
            {
                LoadMapType3();
                return;
            }
            else
            {
                LoadMapType2();
                return;
            }
        }

        //3/4 heroes map format (myth/lifcos i guess)
        if ((Bytes[0] == 0x0D) && (Bytes[1] == 0x4C) && (Bytes[7] == 0x20) && (Bytes[11] == 0x6D))
        {
            LoadMapType7();
            return;
        }

        //if it's none of the above load the default old school format
        LoadMapType0();
    }

    void MapReader::LoadMapType0()
    {
        try
        {
            int offset = 0;
            Width = BitConverter::ToInt16(Bytes, offset);
            offset += 2;
            Height = BitConverter::ToInt16(Bytes, offset);
//C# TO C++ CONVERTER NOTE: The following call to the 'RectangularVectors' helper class reproduces the rectangular array initialization that is automatic in C#:
//ORIGINAL LINE: MapCells = new CellInfo[Width, Height];
            MapCells = RectangularVectors::RectangularCellInfoVector(Width, Height);
            offset = 52;
            for (int x = 0; x < Width; x++)
            {
                for (int y = 0; y < Height; y++)
                { //12
                    MapCells[x][y] = new CellInfo();
                    MapCells[x][y].BackIndex = 0;
                    MapCells[x][y].MiddleIndex = 1;
                    MapCells[x][y].BackImage = static_cast<short>(BitConverter::ToInt16(Bytes, offset));
                    offset += 2;
                    MapCells[x][y].MiddleImage = static_cast<short>(BitConverter::ToInt16(Bytes, offset));
                    offset += 2;
                    MapCells[x][y].FrontImage = static_cast<short>(BitConverter::ToInt16(Bytes, offset));
                    offset += 2;
                    MapCells[x][y].DoorIndex = static_cast<unsigned char>(Bytes[offset++] & 0x7F);
                    MapCells[x][y].DoorOffset = Bytes[offset++];
                    MapCells[x][y].FrontAnimationFrame = Bytes[offset++];
                    MapCells[x][y].FrontAnimationTick = Bytes[offset++];
                    MapCells[x][y].FrontIndex = static_cast<short>(Bytes[offset++] + 2);
                    MapCells[x][y].Light = Bytes[offset++];
                    if ((MapCells[x][y].BackImage & 0x8000) != 0)
                    {
                        MapCells[x][y].BackImage = (MapCells[x][y].BackImage & 0x7FFF) | 0x20000000;
                    }

                    if (MapCells[x][y].Light >= 100 && MapCells[x][y].Light <= 119)
                    {
                        MapCells[x][y].FishingCell = true;
                    }


                }
            }
        }
        catch (const std::runtime_error &ex)
        {
            if (Settings::LogErrors)
            {
                CMain::SaveError(ex.what());
            }
        }

    }

    void MapReader::LoadMapType1()
    {
        try
        {
            int offSet = 21;

            int w = BitConverter::ToInt16(Bytes, offSet);
            offSet += 2;
            int xor_Keyword = BitConverter::ToInt16(Bytes, offSet);
            offSet += 2;
            int h = BitConverter::ToInt16(Bytes, offSet);
            Width = w ^ xor_Keyword;
            Height = h ^ xor_Keyword;
//C# TO C++ CONVERTER NOTE: The following call to the 'RectangularVectors' helper class reproduces the rectangular array initialization that is automatic in C#:
//ORIGINAL LINE: MapCells = new CellInfo[Width, Height];
            MapCells = RectangularVectors::RectangularCellInfoVector(Width, Height);

            offSet = 54;

            for (int x = 0; x < Width; x++)
            {
                for (int y = 0; y < Height; y++)
                {
                    CellInfo *tempVar = new CellInfo();
                    tempVar->BackIndex = 0;
                    tempVar->BackImage = static_cast<int>(BitConverter::ToInt32(Bytes, offSet) ^ 0xAA38AA38);
                    tempVar->MiddleIndex = 1;
                    tempVar->MiddleImage = static_cast<short>(BitConverter::ToInt16(Bytes, offSet += 4) ^ xor_Keyword);
                    tempVar->FrontImage = static_cast<short>(BitConverter::ToInt16(Bytes, offSet += 2) ^ xor_Keyword);
                    tempVar->DoorIndex = static_cast<unsigned char>(Bytes[offSet += 2] & 0x7F);
                    tempVar->DoorOffset = Bytes[++offSet];
                    tempVar->FrontAnimationFrame = Bytes[++offSet];
                    tempVar->FrontAnimationTick = Bytes[++offSet];
                    tempVar->FrontIndex = static_cast<short>(Bytes[++offSet] + 2);
                    tempVar->Light = Bytes[++offSet];
                    tempVar->Unknown = Bytes[++offSet];
                    MapCells[x][y] = tempVar;
                    offSet++;

                    if (MapCells[x][y].Light >= 100 && MapCells[x][y].Light <= 119)
                    {
                        MapCells[x][y].FishingCell = true;
                    }

                    delete tempVar;
                }
            }
        }
        catch (const std::runtime_error &ex)
        {
            if (Settings::LogErrors)
            {
                CMain::SaveError(ex.what());
            }
        }
    }

    void MapReader::LoadMapType2()
    {
        try
        {
            int offset = 0;
            Width = BitConverter::ToInt16(Bytes, offset);
            offset += 2;
            Height = BitConverter::ToInt16(Bytes, offset);
//C# TO C++ CONVERTER NOTE: The following call to the 'RectangularVectors' helper class reproduces the rectangular array initialization that is automatic in C#:
//ORIGINAL LINE: MapCells = new CellInfo[Width, Height];
            MapCells = RectangularVectors::RectangularCellInfoVector(Width, Height);
            offset = 52;
            for (int x = 0; x < Width; x++)
            {
                for (int y = 0; y < Height; y++)
                { //14
                    MapCells[x][y] = new CellInfo();
                    MapCells[x][y].BackImage = static_cast<short>(BitConverter::ToInt16(Bytes, offset));
                    offset += 2;
                    MapCells[x][y].MiddleImage = static_cast<short>(BitConverter::ToInt16(Bytes, offset));
                    offset += 2;
                    MapCells[x][y].FrontImage = static_cast<short>(BitConverter::ToInt16(Bytes, offset));
                    offset += 2;
                    MapCells[x][y].DoorIndex = static_cast<unsigned char>(Bytes[offset++] & 0x7F);
                    MapCells[x][y].DoorOffset = Bytes[offset++];
                    MapCells[x][y].FrontAnimationFrame = Bytes[offset++];
                    MapCells[x][y].FrontAnimationTick = Bytes[offset++];
                    MapCells[x][y].FrontIndex = static_cast<short>(Bytes[offset++] + 120);
                    MapCells[x][y].Light = Bytes[offset++];
                    MapCells[x][y].BackIndex = static_cast<short>(Bytes[offset++] + 100);
                    MapCells[x][y].MiddleIndex = static_cast<short>(Bytes[offset++] + 110);
                    if ((MapCells[x][y].BackImage & 0x8000) != 0)
                    {
                        MapCells[x][y].BackImage = (MapCells[x][y].BackImage & 0x7FFF) | 0x20000000;
                    }

                    if (MapCells[x][y].Light >= 100 && MapCells[x][y].Light <= 119)
                    {
                        MapCells[x][y].FishingCell = true;
                    }
                }
            }
        }
        catch (const std::runtime_error &ex)
        {
            if (Settings::LogErrors)
            {
                CMain::SaveError(ex.what());
            }
        }

    }

    void MapReader::LoadMapType3()
    {
        try
        {
            int offset = 0;
            Width = BitConverter::ToInt16(Bytes, offset);
            offset += 2;
            Height = BitConverter::ToInt16(Bytes, offset);
//C# TO C++ CONVERTER NOTE: The following call to the 'RectangularVectors' helper class reproduces the rectangular array initialization that is automatic in C#:
//ORIGINAL LINE: MapCells = new CellInfo[Width, Height];
            MapCells = RectangularVectors::RectangularCellInfoVector(Width, Height);
            offset = 52;
            for (int x = 0; x < Width; x++)
            {
                for (int y = 0; y < Height; y++)
                { //36
                    MapCells[x][y] = new CellInfo();
                    MapCells[x][y].BackImage = static_cast<short>(BitConverter::ToInt16(Bytes, offset));
                    offset += 2;
                    MapCells[x][y].MiddleImage = static_cast<short>(BitConverter::ToInt16(Bytes, offset));
                    offset += 2;
                    MapCells[x][y].FrontImage = static_cast<short>(BitConverter::ToInt16(Bytes, offset));
                    offset += 2;
                    MapCells[x][y].DoorIndex = static_cast<unsigned char>(Bytes[offset++] & 0x7F);
                    MapCells[x][y].DoorOffset = Bytes[offset++];
                    MapCells[x][y].FrontAnimationFrame = Bytes[offset++];
                    MapCells[x][y].FrontAnimationTick = Bytes[offset++];
                    MapCells[x][y].FrontIndex = static_cast<short>(Bytes[offset++] + 120);
                    MapCells[x][y].Light = Bytes[offset++];
                    MapCells[x][y].BackIndex = static_cast<short>(Bytes[offset++] + 100);
                    MapCells[x][y].MiddleIndex = static_cast<short>(Bytes[offset++] + 110);
                    MapCells[x][y].TileAnimationImage = static_cast<short>(BitConverter::ToInt16(Bytes, offset));
                    offset += 7; //2bytes from tileanimframe, 2 bytes always blank?, 2bytes potentialy 'backtiles index', 1byte fileindex for the backtiles?
                    MapCells[x][y].TileAnimationFrames = Bytes[offset++];
                    MapCells[x][y].TileAnimationOffset = static_cast<short>(BitConverter::ToInt16(Bytes, offset));
                    offset += 14; //tons of light, blending, .. related options i hope
                    if ((MapCells[x][y].BackImage & 0x8000) != 0)
                    {
                        MapCells[x][y].BackImage = (MapCells[x][y].BackImage & 0x7FFF) | 0x20000000;
                    }

                    if (MapCells[x][y].Light >= 100 && MapCells[x][y].Light <= 119)
                    {
                        MapCells[x][y].FishingCell = true;
                    }
                }
            }

        }
        catch (const std::runtime_error &ex)
        {
            if (Settings::LogErrors)
            {
                CMain::SaveError(ex.what());
            }
        }
    }

    void MapReader::LoadMapType4()
    {
        try
        {
            int offset = 31;
            int w = BitConverter::ToInt16(Bytes, offset);
            offset += 2;
            int xor_Keyword = BitConverter::ToInt16(Bytes, offset);
            offset += 2;
            int h = BitConverter::ToInt16(Bytes, offset);
            Width = w ^ xor_Keyword;
            Height = h ^ xor_Keyword;
//C# TO C++ CONVERTER NOTE: The following call to the 'RectangularVectors' helper class reproduces the rectangular array initialization that is automatic in C#:
//ORIGINAL LINE: MapCells = new CellInfo[Width, Height];
            MapCells = RectangularVectors::RectangularCellInfoVector(Width, Height);
            offset = 64;
            for (int x = 0; x < Width; x++)
            {
                for (int y = 0; y < Height; y++)
                { //12
                    MapCells[x][y] = new CellInfo();
                    MapCells[x][y].BackIndex = 0;
                    MapCells[x][y].MiddleIndex = 1;
                    MapCells[x][y].BackImage = static_cast<short>(BitConverter::ToInt16(Bytes, offset) ^ xor_Keyword);
                    offset += 2;
                    MapCells[x][y].MiddleImage = static_cast<short>(BitConverter::ToInt16(Bytes, offset) ^ xor_Keyword);
                    offset += 2;
                    MapCells[x][y].FrontImage = static_cast<short>(BitConverter::ToInt16(Bytes, offset) ^ xor_Keyword);
                    offset += 2;
                    MapCells[x][y].DoorIndex = static_cast<unsigned char>(Bytes[offset++] & 0x7F);
                    MapCells[x][y].DoorOffset = Bytes[offset++];
                    MapCells[x][y].FrontAnimationFrame = Bytes[offset++];
                    MapCells[x][y].FrontAnimationTick = Bytes[offset++];
                    MapCells[x][y].FrontIndex = static_cast<short>(Bytes[offset++] + 2);
                    MapCells[x][y].Light = Bytes[offset++];
                    if ((MapCells[x][y].BackImage & 0x8000) != 0)
                    {
                        MapCells[x][y].BackImage = (MapCells[x][y].BackImage & 0x7FFF) | 0x20000000;
                    }

                    if (MapCells[x][y].Light >= 100 && MapCells[x][y].Light <= 119)
                    {
                        MapCells[x][y].FishingCell = true;
                    }
                }
            }
        }
        catch (const std::runtime_error &ex)
        {
            if (Settings::LogErrors)
            {
                CMain::SaveError(ex.what());
            }
        }
    }

    void MapReader::LoadMapType5()
    {
        try
        {
            unsigned char flag = 0;
            int offset = 20;
            short Attribute = static_cast<short>(BitConverter::ToInt16(Bytes,offset));
            Width = static_cast<int>(BitConverter::ToInt16(Bytes,offset += 2));
            Height = static_cast<int>(BitConverter::ToInt16(Bytes, offset += 2));
            //ignoring eventfile and fogcolor for now (seems unused in maps i checked)
            offset = 28;
            //initiate all cells
//C# TO C++ CONVERTER NOTE: The following call to the 'RectangularVectors' helper class reproduces the rectangular array initialization that is automatic in C#:
//ORIGINAL LINE: MapCells = new CellInfo[Width, Height];
            MapCells = RectangularVectors::RectangularCellInfoVector(Width, Height);
            for (int x = 0; x < Width; x++)
            {
                for (int y = 0; y < Height; y++)
                {
                    MapCells[x][y] = new CellInfo();
                }
            }
            //read all back tiles
            for (int x = 0; x < (Width / 2); x++)
            {
                for (int y = 0; y < (Height / 2); y++)
                {
                    for (int i = 0; i < 4; i++)
                    {
                        MapCells[(x * 2) + (i % 2)][(y * 2) + (i / 2)].BackIndex = static_cast<short>(Bytes[offset] != 255? Bytes[offset] + 200 : -1);
                        MapCells[(x * 2) + (i % 2)][(y * 2) + (i / 2)].BackImage = static_cast<int>(BitConverter::ToUInt16(Bytes, offset + 1) + 1);
                    }
                    offset += 3;
                }
            }
            //read rest of data
            offset = 28 + (3 * ((Width / 2) + (Width % 2)) * (Height / 2));
            for (int x = 0; x < Width; x++)
            {
                for (int y = 0; y < Height; y++)
                {

                    flag = Bytes[offset++];
                    MapCells[x][y].MiddleAnimationFrame = Bytes[offset++];

                    MapCells[x][y].FrontAnimationFrame = Bytes[offset] == 255? static_cast<unsigned char>(0) : Bytes[offset];
                    MapCells[x][y].FrontAnimationFrame &= 0x8F;
                    offset++;
                    MapCells[x][y].MiddleAnimationTick = 0;
                    MapCells[x][y].FrontAnimationTick = 0;
                    MapCells[x][y].FrontIndex = static_cast<short>(Bytes[offset] != 255 ? Bytes[offset] + 200 : -1);
                    offset++;
                    MapCells[x][y].MiddleIndex = static_cast<short>(Bytes[offset] != 255 ? Bytes[offset] + 200 : -1);
                    offset++;
                    MapCells[x][y].MiddleImage = static_cast<unsigned short>(BitConverter::ToUInt16(Bytes,offset) + 1);
                    offset += 2;
                    MapCells[x][y].FrontImage = static_cast<unsigned short>(BitConverter::ToUInt16(Bytes, offset) + 1);
                    if ((MapCells[x][y].FrontImage == 1) && (MapCells[x][y].FrontIndex == 200))
                    {
                        MapCells[x][y].FrontIndex = -1;
                    }
                    offset += 2;
                    offset += 3; //mir3 maps dont have doors so dont bother reading the info
                    MapCells[x][y].Light = static_cast<unsigned char>(Bytes[offset] & 0x0F);
                    offset += 2;
                    if ((flag & 0x01) != 1)
                    {
                        MapCells[x][y].BackImage |= 0x20000000;
                    }
                    if ((flag & 0x02) != 2)
                    {
                        MapCells[x][y].FrontImage = static_cast<unsigned short>(static_cast<unsigned short>(MapCells[x][y].FrontImage) | 0x8000);
                    }

                    if (MapCells[x][y].Light >= 100 && MapCells[x][y].Light <= 119)
                    {
                        MapCells[x][y].FishingCell = true;
                    }
                    else
                    {
                        MapCells[x][y].Light *= 2; //expand general mir3 lighting as default range is small. Might break new colour lights.
                    }
                }
            }
        }
        catch (const std::runtime_error &ex)
        {
            if (Settings::LogErrors)
            {
                CMain::SaveError(ex.what());
            }
        }
    }

    void MapReader::LoadMapType6()
    {
        try
        {
            unsigned char flag = 0;
            int offset = 16;
            Width = BitConverter::ToInt16(Bytes, offset);
            offset += 2;
            Height = BitConverter::ToInt16(Bytes, offset);
//C# TO C++ CONVERTER NOTE: The following call to the 'RectangularVectors' helper class reproduces the rectangular array initialization that is automatic in C#:
//ORIGINAL LINE: MapCells = new CellInfo[Width, Height];
            MapCells = RectangularVectors::RectangularCellInfoVector(Width, Height);
            offset = 40;
            for (int x = 0; x < Width; x++)
            {
                for (int y = 0; y < Height; y++)
                {
                    MapCells[x][y] = new CellInfo();
                    flag = Bytes[offset++];
                    MapCells[x][y].BackIndex = static_cast<short>(Bytes[offset] != 255 ? Bytes[offset] + 300 : -1);
                    offset++;
                    MapCells[x][y].MiddleIndex = static_cast<short>(Bytes[offset] != 255 ? Bytes[offset] + 300 : -1);
                    offset++;
                    MapCells[x][y].FrontIndex = static_cast<short>(Bytes[offset] != 255 ? Bytes[offset] + 300 : -1);
                    offset++;
                    MapCells[x][y].BackImage = static_cast<short>(BitConverter::ToInt16(Bytes, offset) + 1);
                    offset += 2;
                    MapCells[x][y].MiddleImage = static_cast<short>(BitConverter::ToInt16(Bytes, offset) + 1);
                    offset += 2;
                    MapCells[x][y].FrontImage = static_cast<short>(BitConverter::ToInt16(Bytes, offset) + 1);
                    offset += 2;
                    if ((MapCells[x][y].FrontImage == 1) && (MapCells[x][y].FrontIndex == 200))
                    {
                        MapCells[x][y].FrontIndex = -1;
                    }
                    MapCells[x][y].MiddleAnimationFrame = Bytes[offset++];
                    MapCells[x][y].FrontAnimationFrame = Bytes[offset] == 255 ? static_cast<unsigned char>(0) : Bytes[offset];
                    if (MapCells[x][y].FrontAnimationFrame > 0x0F) //assuming shanda used same value not sure
                    {
                        MapCells[x][y].FrontAnimationFrame = static_cast<unsigned char>((MapCells[x][y].FrontAnimationFrame & 0x0F));
                    }
                    offset++;
                    MapCells[x][y].MiddleAnimationTick = 1;
                    MapCells[x][y].FrontAnimationTick = 1;
                    MapCells[x][y].Light = static_cast<unsigned char>(Bytes[offset] & 0x0F);
                    MapCells[x][y].Light *= 4; //far wants all light on mir3 maps to be maxed :p
                    offset += 8;
                    if ((flag & 0x01) != 1)
                    {
                        MapCells[x][y].BackImage |= 0x20000000;
                    }
                    if ((flag & 0x02) != 2)
                    {
                        MapCells[x][y].FrontImage = static_cast<short>(static_cast<unsigned short>(MapCells[x][y].FrontImage) | 0x8000);
                    }

                }
            }
        }
        catch (const std::runtime_error &ex)
        {
            if (Settings::LogErrors)
            {
                CMain::SaveError(ex.what());
            }
        }

    }

    void MapReader::LoadMapType7()
    {
        try
        {
            int offset = 21;
            Width = BitConverter::ToInt16(Bytes, offset);
            offset += 4;
            Height = BitConverter::ToInt16(Bytes, offset);
//C# TO C++ CONVERTER NOTE: The following call to the 'RectangularVectors' helper class reproduces the rectangular array initialization that is automatic in C#:
//ORIGINAL LINE: MapCells = new CellInfo[Width, Height];
            MapCells = RectangularVectors::RectangularCellInfoVector(Width, Height);

            offset = 54;

            for (int x = 0; x < Width; x++)
            {
                for (int y = 0; y < Height; y++)
                { //total 15
                    CellInfo *tempVar = new CellInfo();
                    tempVar->BackIndex = 0;
                    tempVar->BackImage = static_cast<int>(BitConverter::ToInt32(Bytes, offset));
                    tempVar->MiddleIndex = 1;
                    tempVar->MiddleImage = static_cast<short>(BitConverter::ToInt16(Bytes, offset += 4));
                    tempVar->FrontImage = static_cast<short>(BitConverter::ToInt16(Bytes, offset += 2));
                    tempVar->DoorIndex = static_cast<unsigned char>(Bytes[offset += 2] & 0x7F);
                    tempVar->DoorOffset = Bytes[++offset];
                    tempVar->FrontAnimationFrame = Bytes[++offset];
                    tempVar->FrontAnimationTick = Bytes[++offset];
                    tempVar->FrontIndex = static_cast<short>(Bytes[++offset] + 2);
                    tempVar->Light = Bytes[++offset];
                    tempVar->Unknown = Bytes[++offset];
                    MapCells[x][y] = tempVar;
                    if ((MapCells[x][y].BackImage & 0x8000) != 0)
                    {
                        MapCells[x][y].BackImage = (MapCells[x][y].BackImage & 0x7FFF) | 0x20000000;
                    }
                    offset++;

                    if (MapCells[x][y].Light >= 100 && MapCells[x][y].Light <= 119)
                    {
                        MapCells[x][y].FishingCell = true;
                    }

                    delete tempVar;
                }
            }
        }
        catch (const std::runtime_error &ex)
        {
            if (Settings::LogErrors)
            {
                CMain::SaveError(ex.what());
            }
        }
    }

    void MapReader::LoadMapType100()
    {
        try
        {
            int offset = 4;
            if ((Bytes[0] != 1) || (Bytes[1] != 0))
            {
                return; //only support version 1 atm
            }
            Width = BitConverter::ToInt16(Bytes, offset);
            offset += 2;
            Height = BitConverter::ToInt16(Bytes, offset);
//C# TO C++ CONVERTER NOTE: The following call to the 'RectangularVectors' helper class reproduces the rectangular array initialization that is automatic in C#:
//ORIGINAL LINE: MapCells = new CellInfo[Width, Height];
            MapCells = RectangularVectors::RectangularCellInfoVector(Width, Height);
            offset = 8;
            for (int x = 0; x < Width; x++)
            {
                for (int y = 0; y < Height; y++)
                {
                    MapCells[x][y] = new CellInfo();
                    MapCells[x][y].BackIndex = static_cast<short>(BitConverter::ToInt16(Bytes, offset));
                    offset += 2;
                    MapCells[x][y].BackImage = static_cast<int>(BitConverter::ToInt32(Bytes, offset));
                    offset += 4;
                    MapCells[x][y].MiddleIndex = static_cast<short>(BitConverter::ToInt16(Bytes, offset));
                    offset += 2;
                    MapCells[x][y].MiddleImage = static_cast<short>(BitConverter::ToInt16(Bytes, offset));
                    offset += 2;
                    MapCells[x][y].FrontIndex = static_cast<short>(BitConverter::ToInt16(Bytes, offset));
                    offset += 2;
                    MapCells[x][y].FrontImage = static_cast<short>(BitConverter::ToInt16(Bytes, offset));
                    offset += 2;
                    MapCells[x][y].DoorIndex = static_cast<unsigned char>(Bytes[offset++] & 0x7F);
                    MapCells[x][y].DoorOffset = Bytes[offset++];
                    MapCells[x][y].FrontAnimationFrame = Bytes[offset++];
                    MapCells[x][y].FrontAnimationTick = Bytes[offset++];
                    MapCells[x][y].MiddleAnimationFrame = Bytes[offset++];
                    MapCells[x][y].MiddleAnimationTick = Bytes[offset++];
                    MapCells[x][y].TileAnimationImage = static_cast<short>(BitConverter::ToInt16(Bytes, offset));
                    offset += 2;
                    MapCells[x][y].TileAnimationOffset = static_cast<short>(BitConverter::ToInt16(Bytes, offset));
                    offset += 2;
                    MapCells[x][y].TileAnimationFrames = Bytes[offset++];
                    MapCells[x][y].Light = Bytes[offset++];

                    if (MapCells[x][y].Light >= 100 && MapCells[x][y].Light <= 119)
                    {
                        MapCells[x][y].FishingCell = true;
                    }
                }
            }
        }
        catch (const std::runtime_error &ex)
        {
            if (Settings::LogErrors)
            {
                CMain::SaveError(ex.what());
            }
        }
    }
}
